package com.meshnetics.gb.stack.core;

import com.meshnetics.gb.stack.core.config.IBParamParser;
import com.meshnetics.gb.type.DataType;

import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;

/**
 * Base thread-safe implementation of InformationBase.
 *
 * @author mmarkov
 */
public class InformationBaseImpl implements InformationBase {
    /** The parameters by name map. */
    protected final Map paramsByName = new HashMap();

    /** The parameters by code map. */
    protected final Map paramsByCode = new HashMap();

    public synchronized IBParameter getParameter(String name) {
        return (IBParameter) paramsByName.get(name);
    }

    public synchronized IBParameter getParameter(int code) {
        return (IBParameter) paramsByCode.get(new Integer(code));
    }

    public synchronized Object getValue(String name) {
        IBParameter param = (IBParameter) paramsByName.get(name);
        return (param != null) ? param.getValue() : null;
    }

    public synchronized Object getValue(int code) { // todo -- by yaserchev -- to prevent NPE 
        final IBParameter ibParam = (IBParameter) paramsByCode.get(new Integer(code));
        return ibParam == null ? null : ibParam.getValue();
    }

    public synchronized IBParameter addParameter(IBParameter param) {
        paramsByName.put(param.getName(), param);
        paramsByCode.put(new Integer(param.getCode()), param);
        return param;
    }

    public synchronized IBParameter removeParameter(String name) {
        IBParameter param = (IBParameter) paramsByName.remove(name);

        if (param != null) {
            paramsByCode.remove(Integer.valueOf(param.getCode()));
        }
        return param;
    }

    public synchronized IBParameter removeParameter(int code) {
        IBParameter param = (IBParameter) paramsByCode.remove(new Integer(code));

        if (param != null) {
            paramsByName.remove(param.getName());
        }
        return param;
    }

    public synchronized Collection getParameters() {
        return paramsByName.values();
    }

    public synchronized void reset() {
        for (Iterator iter = paramsByName.values().iterator(); iter.hasNext();) {
            ((IBParameter) iter.next()).reset();
        }
    }

    public synchronized void reset(String name) {
        ((IBParameter) paramsByName.get(name)).reset();
    }

    public synchronized void setData(InformationBase ib) {
        Collection ibParams = ib.getParameters();

        if (ibParams != null) {
            for (Iterator iter = ibParams.iterator(); iter.hasNext();) {
                IBParameter param = (IBParameter) iter.next();
                IBParameter oldParam = (IBParameter) paramsByName.get(param.getName());

                if (oldParam == null) {
                    addParameter(param);
                } else {
                    DataType type = oldParam.getType();
                    Object value;

                    if (type != null) {
                        // this is StackLayer type
                        value = type.valueOf((String) param.getValue());
                    } else {
                        // this is non-StackLayer type
                        Object oldValue = oldParam.getValue();
                        value = IBParamParser.getValue(oldValue.getClass(), (String) param.getValue());
                    }
                    oldParam.setValue(value);
                    oldParam.setDefaultValue(value);
                }
            }
        }
    }

    public synchronized Object clone() {
        InformationBaseImpl ib = new InformationBaseImpl();

        for (Iterator iter = paramsByName.values().iterator(); iter.hasNext();) {
            ib.addParameter((IBParameter) iter.next());
        }
        return ib;
    }

    /**
     * Basic implementation does nothing.
     */
    public void save(String file) throws IOException {
    }
}
